package com.yy.auth.server.config;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import com.yy.auth.server.util.KeyGeneratorUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeRequestAuthenticationConverter;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2DeviceVerificationAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.DelegatingAuthenticationConverter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;

import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * @Description 授权服务器配置
 * @Date 2025/10/10 上午10:14
 * @Author yanglin
 **/
@Configuration
public class AuthServerConfig {
    /**
     * 注册客户端
     * @return
     */
    //@Bean
    //public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) {
    //    // 使用 BCrypt 编码密码
    //    String rawSecret = "secret";
    //    String encodedSecret = passwordEncoder.encode(rawSecret);
    //    // 验证密码匹配
    //    boolean matches = passwordEncoder.matches(rawSecret, encodedSecret);
    //    if (!matches) {
    //        throw new IllegalStateException("[SSO-AUTH-SERVER] Password encoding failed");
    //    }
    //    RegisteredClient client1 = RegisteredClient.withId(UUID.randomUUID().toString())
    //            .clientId("client1")
    //            //.clientSecret("{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG") // secret
    //            //.clientSecret("{bcrypt}" + encodedSecret)
    //            .clientSecret(encodedSecret)
    //            .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
    //            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
    //            .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
    //            .redirectUri("http://localhost:8081/login/oauth2/code/client1")
    //            .redirectUri("http://localhost:8082/login/oauth2/code/client1")
    //            .scope(OidcScopes.OPENID)
    //            .scope("read")
    //            // 应用TokenSettings
    //            .tokenSettings(tokenSettings())
    //            // 设置只需登录一次
    //            .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
    //            .build();
    //
    //    return new InMemoryRegisteredClientRepository(client1);
    //}

    /**
     * 配置多个客户端
     * @param passwordEncoder
     * @return
     */
    @Bean
    public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) {
        List<RegisteredClient> clients = new ArrayList<>();

        // 应用1配置
        RegisteredClient app1Client = createClient(
                "client11",
                "http://localhost:8081/login/oauth2/code/client1",
                passwordEncoder
        );

        // 应用2配置
        RegisteredClient app2Client = createClient(
                "client21",
                "http://localhost:8082/login/oauth2/code/client2",
                passwordEncoder
        );
        clients.add(app1Client);
        clients.add(app2Client);
        // 验证唯一性
        validateClientUniqueness(clients);

        return new InMemoryRegisteredClientRepository(clients);
    }

    private RegisteredClient createClient(String clientId, String redirectUri, PasswordEncoder passwordEncoder) {
        String rawSecret = "secret";
        String encodedSecret = passwordEncoder.encode(rawSecret);

        return RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId(clientId)
                .clientSecret(encodedSecret)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .redirectUri(redirectUri)
                .scope(OidcScopes.OPENID)
                .scope("read")
                .tokenSettings(tokenSettings())
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
                .build();
    }

    private void validateClientUniqueness(List<RegisteredClient> clients) {
        Set<String> clientIds = new HashSet<>();
        Set<String> redirectUris = new HashSet<>();

        for (RegisteredClient client : clients) {
            // 检查clientId唯一性
            if (clientIds.contains(client.getClientId())) {
                throw new IllegalStateException("Duplicate client ID: " + client.getClientId());
            }
            clientIds.add(client.getClientId());

            // 检查重定向URI唯一性
            for (String uri : client.getRedirectUris()) {
                if (redirectUris.contains(uri)) {
                    throw new IllegalStateException("Duplicate redirect URI: " + uri);
                }
                redirectUris.add(uri);
            }
        }
    }

    /**
     * 在 Spring Authorization Server 1.5.2 中，
     * ProviderSettings已被重命名为 AuthorizationServerSettings。
     *
     * @return
     */
    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder()
                .issuer("http://localhost:9000")
                .build();
    }

    @Bean
    public TokenSettings tokenSettings() {
        return TokenSettings.builder()
                // 设置授权码有效期为 10 分钟
                .authorizationCodeTimeToLive(Duration.ofMinutes(10))
                // 设置访问令牌有效期
                .accessTokenTimeToLive(Duration.ofHours(1))
                // 设置刷新令牌有效期
                .refreshTokenTimeToLive(Duration.ofDays(30))
                .build();
    }

}
